﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoroMoro.Samples.ToDoList.Base.Application;
using MoroMoro.Samples.ToDoList.Application;
using MoroMoro.Samples.ToDoList.Application.Categories;
using MoroMoro.Samples.ToDoList.Domain.ToDos;
using MoroMoro.Samples.ToDoList.Domain.Categories;
using MoroMoro.Samples.ToDoList.Presentation.Views.ToDos;
using MoroMoro.Samples.ToDoList.Presentation.ErrorMessages.ToDos;
using MoroMoro.Samples.ToDoList.Presentation.Utils;

namespace MoroMoro.Samples.ToDoList.Presentation.Presenters.ToDos
{
    /// <summary>
    /// ToDo 構築プレゼンターです。
    /// </summary>
    /// <typeparam name="TView">ビューの型。</typeparam>
    /// <typeparam name="TErrors">エラーの型。</typeparam>
    public abstract class ToDoBuildPresenter<TView, TErrors> : BuildPresenter<TView, ToDo, ToDo.Builder, TErrors>
        where TView : IToDoBuildView
        where TErrors : BuildErrors
    {
        /// <summary>
        /// <see cref="ToDoBuildPresenter&lt;TView, TErrors&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="view">ビュー。</param>
        /// <param name="facade">ファサード。</param>
        /// <param name="builder">ビルダ。</param>
        /// <exception cref="System.ArgumentNullException">view または facade または builder が null です。</exception>
        public ToDoBuildPresenter(TView view, ToDoListFacade facade, ToDo.Builder builder)
            : base(view, facade, builder)
        {
        }


        /// <inheritdoc/>
        protected override void RegisterEventHandlers()
        {
            base.RegisterEventHandlers();

            View.TitleTextChanged += OnTitleTextChanged;
            View.SelectedCategoryChanged += OnSelectedCategoryChanged;
            View.MemoAdditionButtonClick += OnMemoAdditionButtonClick;
            View.MemoRemoveButtonClick += OnMemoRemoveButtonClick;
        }

        /// <inheritdoc/>
        protected override void OnLoad(object sender, EventArgs e)
        {
            base.OnLoad(sender, e);

            BindCategories();
        }

        /// <summary>
        /// ToDo のタイトル入力フィールドのテキストが変更された時の処理を行います。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnTitleTextChanged(object sender, EventArgs e)
        {
            if (string.Equals(Builder.Title, View.Title, StringComparison.Ordinal))
            {
                return;
            }
            Builder.Title = View.Title;
            HasChange = true;
            UpdateInputErrors();
        }

        /// <summary>
        /// ToDo のカテゴリ入力フィールドの選択項目が変更された時の処理を行います。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnSelectedCategoryChanged(object sender, EventArgs e)
        {
            Builder.Category = View.Category;
        }

        /// <summary>
        /// ToDo のメモ追加ボタンがクリックされた時の処理を行います。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnMemoAdditionButtonClick(object sender, EventArgs e)
        {
            Builder.MemoBuilders.Add(Builder.CreateMemoBuilder());
            View.AddMemoArea(OnMemoTextChanged);
            View.SelectedMemoTabPageIndex = -1;
            View.SelectedMemoTabPageIndex = View.MemoTabPagesCount - 1;

            HasChange = true;
            UpdateInputErrors();
        }

        /// <summary>
        /// ToDo のメモ削除ボタンがクリックされた時の処理を行います。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnMemoRemoveButtonClick(object sender, EventArgs e)
        {
            var memoIndex = View.SelectedMemoTabPageIndex;
            Builder.MemoBuilders.RemoveAt(memoIndex);
            View.RemoveMemoArea(memoIndex);
            View.SelectedMemoTabPageIndex = (memoIndex < View.MemoTabPagesCount) ? memoIndex : (memoIndex - 1);

            HasChange = true;
            UpdateInputErrors();
        }

        /// <summary>
        /// ToDo のメモテキスト入力フィールドのテキストが変更された時の処理を行います。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnMemoTextChanged(object sender, MemoEventArgs e)
        {
            if (string.Equals(Builder.MemoBuilders[e.MemoIndex].Text, View.GetMemoText(e.MemoIndex), StringComparison.Ordinal))
            {
                return;
            }
            Builder.MemoBuilders[e.MemoIndex].Text = View.GetMemoText(e.MemoIndex);
            HasChange = true;
            UpdateInputErrors();
        }


        /// <summary>
        /// ToDo のカテゴリ入力フィールドのデータソースをバインドします。
        /// </summary>
        private void BindCategories()
        {
            var categoryCaptions = new ComboBoxDataSource<Category>();
            categoryCaptions.Add(null, "未分類");
            categoryCaptions.AddRange(Facade.CategoryList, item => item.Name);

            View.BindCategories(categoryCaptions, "Value", "Text");
        }


        /// <inheritdoc/>
        protected override void UpdateInputErrors()
        {
            var toDoBuildErrorMessage = new ToDoBuildErrorMessage();

            Builder.NotifyTitleErrorTo(toDoBuildErrorMessage);
            View.SetTitleError(toDoBuildErrorMessage.ToString());
            toDoBuildErrorMessage.Clear();

            Builder.NotifyMemosErrorTo(toDoBuildErrorMessage);
            View.SetMemoListError(toDoBuildErrorMessage.ToString());
            toDoBuildErrorMessage.Clear();

            var memoBuildErrorMessage = new MemoBuildErrorMessage();
            for (int i = 0; i < Builder.MemoBuilders.Count; i++)
            {
                Builder.MemoBuilders[i].NotifyTextErrorTo(memoBuildErrorMessage);
                View.SetMemoTextError(i, memoBuildErrorMessage.ToString());
                memoBuildErrorMessage.Clear();
            }
        }
    }
}
